/*
 * serial_manager.cpp
 * 串口调试工具 - 串口管理模块源文件
 * 
 * 此文件包含SerialManager类的实现，负责串口扫描、参数配置和连接管理功能。
 */

#include "serial_manager.h"
#include <QMessageBox>
#include <QSerialPortInfo>
#include <QDateTime>
#include <QDebug>

// 构造函数实现
SerialManager::SerialManager(QObject *parent) : QObject(parent)
{
    // 初始化串口对象
    serialPort = new QSerialPort(this);
    
    // 初始化串口信息缓存
    portInfoCache.clear();
    
    // 初始化端口检测定时器
    portCheckTimer = new QTimer(this);
    connect(portCheckTimer, &QTimer::timeout, this, &SerialManager::checkSerialPortsAvailability);
    
    // 设置默认检测间隔为5秒
    portCheckTimer->setInterval(5000);
    
    // 初始化数据位缓存
    portSupportedDataBitsCache.clear();

    // 连接串口事件
    connect(serialPort, &QSerialPort::readyRead, this, &SerialManager::readData);
    connect(serialPort, &QSerialPort::errorOccurred, this, &SerialManager::handleError);
}

// 析构函数实现
SerialManager::~SerialManager()
{
    // 确保在析构前断开连接
    disconnectPort();
    
    // 停止定时器
    if (portCheckTimer->isActive()) {
        portCheckTimer->stop();
    }
    
    // 清理资源
    delete portCheckTimer;
    delete serialPort;
}

// 初始化串口参数
void SerialManager::setupSerialPort()
{
    // 设置默认参数
    serialPort->setBaudRate(QSerialPort::Baud115200);
    serialPort->setDataBits(QSerialPort::Data8);
    serialPort->setStopBits(QSerialPort::OneStop);
    serialPort->setParity(QSerialPort::NoParity);
    serialPort->setFlowControl(QSerialPort::NoFlowControl);
}

// 扫描并填充可用串口列表
QStringList SerialManager::populatePortList()
{
    QStringList availablePorts;
    
    // 获取所有可用串口信息
    const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
    
    // 更新端口信息缓存
    updatePortStatusCache();
    
    // 从缓存中提取可用端口信息
    for (auto it = portInfoCache.constBegin(); it != portInfoCache.constEnd(); ++it) {
        const SerialPortInfo &info = it.value();
        availablePorts << info.displayText;
    }
    
    return availablePorts;
}

// 快速填充串口列表（不进行详细检测）
QStringList SerialManager::populatePortListFast()
{
    QStringList availablePorts;
    
    // 获取所有可用串口信息
    const QList<QSerialPortInfo> ports = QSerialPortInfo::availablePorts();
    
    // 快速构建端口列表
    for (const QSerialPortInfo &portInfo : ports) {
        QString displayText = portInfo.portName();
        
        // 添加端口描述（如果有）
        if (!portInfo.description().isEmpty()) {
            displayText += " (" + portInfo.description() + ")";
        }
        
        availablePorts << displayText;
    }
    
    return availablePorts;
}

// 填充波特率列表
QStringList SerialManager::populateBaudRateList()
{
    QStringList baudRates;
    
    // 常用波特率列表
    baudRates << "9600" << "19200" << "38400" << "57600" << "115200" << "230400" << "460800" << "921600" << "1000000" << "1500000" << "2000000" << "3000000";
    
    return baudRates;
}

// 填充数据位列表
QStringList SerialManager::populateDataBitsList()
{
    QStringList dataBits;
    
    dataBits << "5" << "6" << "7" << "8";
    
    return dataBits;
}

// 填充停止位列表
QStringList SerialManager::populateStopBitsList()
{
    QStringList stopBits;
    
    stopBits << "1" << "1.5" << "2";
    
    return stopBits;
}

// 填充校验位列表
QStringList SerialManager::populateParityList()
{
    QStringList parity;
    
    parity << "None" << "Even" << "Odd" << "Mark" << "Space";
    
    return parity;
}

// 填充流控制列表
QStringList SerialManager::populateFlowControlList()
{
    QStringList flowControl;
    
    flowControl << "None" << "RTS/CTS" << "XON/XOFF";
    
    return flowControl;
}

// 检测并更新串口状态缓存
void SerialManager::updatePortStatusCache()
{
    // 记录检测时间
    lastPortCheckTime = QDateTime::currentDateTime();
    
    // 获取系统当前所有串口
    const QList<QSerialPortInfo> availablePorts = QSerialPortInfo::availablePorts();
    
    // 用于记录哪些端口仍然存在
    QSet<QString> stillAvailablePortNames;
    
    // 更新现有端口信息
    for (const QSerialPortInfo &portInfo : availablePorts) {
        QString portName = portInfo.portName();
        stillAvailablePortNames.insert(portName);
        
        // 如果端口已在缓存中，更新其信息
        if (portInfoCache.contains(portName)) {
            SerialPortInfo &cachedInfo = portInfoCache[portName];
            
            // 更新可用状态和描述
            cachedInfo.isAvailable = true;
            cachedInfo.description = portInfo.description();
            cachedInfo.lastCheckTime = lastPortCheckTime;
            
            // 如果串口正在被本应用使用，则标记为已连接
            cachedInfo.isConnectedByApp = (serialPort->portName() == portName && serialPort->isOpen());
            
            // 检查是否被其他应用占用
            cachedInfo.isBusyByOther = checkPortBusy(portName);
            cachedInfo.status = cachedInfo.isBusyByOther ? SerialPortInfo::Busy : SerialPortInfo::Available;
            
            // 更新显示文本
            updatePortDisplayText(cachedInfo);
        } else {
            // 新端口，创建新的缓存项
            SerialPortInfo newInfo;
            newInfo.portName = portName;
            newInfo.description = portInfo.description();
            newInfo.isAvailable = true;
            newInfo.isConnectedByApp = (serialPort->portName() == portName && serialPort->isOpen());
            newInfo.isBusyByOther = checkPortBusy(portName);
            newInfo.lastCheckTime = lastPortCheckTime;
            newInfo.dataBitsChecked = false;
            newInfo.status = newInfo.isBusyByOther ? SerialPortInfo::Busy : SerialPortInfo::Available;
            
            // 更新显示文本
            updatePortDisplayText(newInfo);
            
            // 添加到缓存
            portInfoCache[portName] = newInfo;
        }
    }
    
    // 标记不再可用的端口
    QList<QString> portsToRemove;
    for (auto it = portInfoCache.begin(); it != portInfoCache.end(); ++it) {
        SerialPortInfo &info = it.value();
        
        // 如果端口不再可用，更新其状态
        if (!stillAvailablePortNames.contains(info.portName)) {
            info.isAvailable = false;
            info.isConnectedByApp = false;
            info.lastCheckTime = lastPortCheckTime;
            info.status = SerialPortInfo::NotFound;
            
            // 更新显示文本
            updatePortDisplayText(info);
            
            // 标记为可删除（如果很长时间都不可用）
            if (info.lastAvailableTime.isValid() && 
                info.lastAvailableTime.secsTo(lastPortCheckTime) > 30) {
                portsToRemove << it.key();
            } else if (!info.isAvailable) {
                // 记录最后可用时间
                info.lastAvailableTime = lastPortCheckTime;
            }
        }
    }
    
    // 移除长时间不可用的端口
    for (const QString &portName : portsToRemove) {
        portInfoCache.remove(portName);
    }
}

// 检查端口是否被占用
bool SerialManager::checkPortBusy(const QString &portName)
{
    // 如果是本应用正在使用的端口，直接返回false
    if (serialPort->portName() == portName && serialPort->isOpen()) {
        return false;
    }
    
    // 创建临时串口对象来尝试打开端口
    QSerialPort tempPort;
    tempPort.setPortName(portName);
    
    bool isAvailable = tempPort.open(QIODevice::ReadWrite);
    if (isAvailable) {
        tempPort.close();
        return false; // 端口可打开，未被占用
    } else {
        return true; // 端口不可打开，可能被占用
    }
}

// 更新端口显示文本
void SerialManager::updatePortDisplayText(SerialPortInfo &info)
{
    QString displayText = info.portName;
    
    // 添加端口描述（如果有）
    if (!info.description.isEmpty()) {
        displayText += " (" + info.description + ")";
    }
    
    // 添加端口状态标记
    if (info.isConnectedByApp) {
        displayText += " [已连接]";
    } else if (info.isAvailable) {
        if (info.isBusyByOther) {
            displayText += " [已占用]";
        }
    } else {
        displayText += " [已断开]";
    }
    
    info.displayText = displayText;
}

// 定时检测串口可用性
void SerialManager::checkSerialPortsAvailability()
{
    // 更新端口状态缓存
    updatePortStatusCache();
    
    // 发出信号通知端口列表可能已变更
    emit portStatusChanged();
}

// 开始自动检测串口
void SerialManager::startPortDetection()
{
    if (!portCheckTimer->isActive()) {
        portCheckTimer->start();
    }
}

// 停止自动检测串口
void SerialManager::stopPortDetection()
{
    if (portCheckTimer->isActive()) {
        portCheckTimer->stop();
    }
}

// 设置串口参数
bool SerialManager::setPortParameters(const QString &portName, int baudRate, 
                                     const QString &dataBits, const QString &stopBits, 
                                     const QString &parity, const QString &flowControl)
{
    // 先断开现有连接
    if (serialPort->isOpen()) {
        serialPort->close();
    }
    
    // 设置端口名称
    serialPort->setPortName(portName);
    
    // 设置波特率
    serialPort->setBaudRate(baudRate);
    
    // 设置数据位
    if (dataBits == "5") serialPort->setDataBits(QSerialPort::Data5);
    else if (dataBits == "6") serialPort->setDataBits(QSerialPort::Data6);
    else if (dataBits == "7") serialPort->setDataBits(QSerialPort::Data7);
    else serialPort->setDataBits(QSerialPort::Data8);
    
    // 设置停止位
    if (stopBits == "1") serialPort->setStopBits(QSerialPort::OneStop);
    else if (stopBits == "1.5") serialPort->setStopBits(QSerialPort::OneAndHalfStop);
    else serialPort->setStopBits(QSerialPort::TwoStop);
    
    // 设置校验位
    if (parity == "None") serialPort->setParity(QSerialPort::NoParity);
    else if (parity == "Even") serialPort->setParity(QSerialPort::EvenParity);
    else if (parity == "Odd") serialPort->setParity(QSerialPort::OddParity);
    else if (parity == "Mark") serialPort->setParity(QSerialPort::MarkParity);
    else serialPort->setParity(QSerialPort::SpaceParity);
    
    // 设置流控制
    if (flowControl == "None") serialPort->setFlowControl(QSerialPort::NoFlowControl);
    else if (flowControl == "RTS/CTS") serialPort->setFlowControl(QSerialPort::HardwareControl);
    else serialPort->setFlowControl(QSerialPort::SoftwareControl);
    
    return true;
}

// 连接到串口
bool SerialManager::connectPort()
{
    // 如果已连接，先断开
    if (serialPort->isOpen()) {
        serialPort->close();
    }
    
    // 尝试打开串口
    bool success = serialPort->open(QIODevice::ReadWrite);
    
    if (success) {
        // 连接成功，更新端口状态
        QString portName = serialPort->portName();
        if (portInfoCache.contains(portName)) {
            portInfoCache[portName].isConnectedByApp = true;
            portInfoCache[portName].isBusyByOther = false;
            updatePortDisplayText(portInfoCache[portName]);
        }
        
        // 发出连接状态变化信号
        emit connectionStatusChanged(true);
    } else {
        // 连接失败，记录并发出错误信号
        lastError = serialPort->errorString();
        emit errorOccurred(lastError);
    }
    
    return success;
}

// 断开串口连接

// 获取串口连接状态
bool SerialManager::isPortConnected() const
{
    return serialPort->isOpen();
}

// 获取当前连接的端口名称
QString SerialManager::getCurrentPortName() const
{
    if (serialPort->isOpen()) {
        return serialPort->portName();
    }
    return QString();
}

// 检测串口支持的数据位
QList<QSerialPort::DataBits> SerialManager::detectSupportedDataBits(const QString &portName)
{
    QList<QSerialPort::DataBits> supportedDataBits;
    
    // 检查缓存
    if (portSupportedDataBitsCache.contains(portName)) {
        const QList<QSerialPort::DataBits> &cachedBits = portSupportedDataBitsCache[portName];
        for (QSerialPort::DataBits bits : cachedBits) {
            supportedDataBits << bits;
        }
        
        portSupportedDataBitsCache[portName] = supportedDataBits;
        
        return supportedDataBits;
    }
    
    // 创建临时串口对象用于检测
    QSerialPort tempPort;
    tempPort.setPortName(portName);
    
    // 支持的数据位选项
    QList<QSerialPort::DataBits> testDataBits = {
        QSerialPort::Data8,
        QSerialPort::Data7,
        QSerialPort::Data6,
        QSerialPort::Data5
    };
    
    // 尝试打开端口
    if (tempPort.open(QIODevice::ReadWrite)) {
        // 保存当前配置
        QSerialPort::DataBits currentDataBits = tempPort.dataBits();
        QSerialPort::StopBits currentStopBits = tempPort.stopBits();
        QSerialPort::Parity currentParity = tempPort.parity();
        
        // 测试每种数据位配置
        for (QSerialPort::DataBits bits : testDataBits) {
            bool isSupported = true;
            
            // 设置数据位
            tempPort.setDataBits(bits);
            
            // 测试不同的停止位和校验位组合
            QList<QSerialPort::StopBits> testStopBits = {QSerialPort::OneStop, QSerialPort::TwoStop};
            QList<QSerialPort::Parity> testParity = {QSerialPort::NoParity, QSerialPort::EvenParity, QSerialPort::OddParity};
            
            for (QSerialPort::StopBits sb : testStopBits) {
                tempPort.setStopBits(sb);
                for (QSerialPort::Parity p : testParity) {
                    tempPort.setParity(p);
                    
                    // 检查配置是否成功
                    if (tempPort.dataBits() != bits || 
                        tempPort.stopBits() != sb || 
                        tempPort.parity() != p) {
                        isSupported = false;
                        break;
                    }
                }
                if (!isSupported) break;
            }
            
            // 如果配置支持，添加到列表
            if (isSupported) {
                supportedDataBits << bits;
            }
        }
        
        // 恢复原始配置
        tempPort.setDataBits(currentDataBits);
        tempPort.setStopBits(currentStopBits);
        tempPort.setParity(currentParity);
        
        // 关闭临时端口
        tempPort.close();
    }
    
    // 如果没有检测到任何支持的数据位，默认假设支持8位
    if (supportedDataBits.isEmpty()) {
        supportedDataBits << QSerialPort::Data8;
    }
    
    // 更新缓存
    QStringList cachedBits;
    for (QSerialPort::DataBits bits : supportedDataBits) {
        switch (bits) {
        case QSerialPort::Data5: cachedBits << "5";
            break;
        case QSerialPort::Data6: cachedBits << "6";
            break;
        case QSerialPort::Data7: cachedBits << "7";
            break;
        case QSerialPort::Data8: cachedBits << "8";
            break;
        default:
            break;
        }
    }
    portSupportedDataBitsCache[portName] = supportedDataBits;
    
    return supportedDataBits;
}

// 获取串口对象指针
QSerialPort* SerialManager::getSerialPort() const
{
    return serialPort;
}

// 发送串口数据
qint64 SerialManager::sendData(const QByteArray &data)
{
    if (!serialPort->isOpen()) {
        lastError = QString("串口未连接");
        return -1;
    }
    return serialPort->write(data);
}

// 获取串口错误
QString SerialManager::getLastError() const
{
    return lastError;
}

// 读取串口数据
void SerialManager::readData()
{
    QByteArray data = serialPort->readAll();
    if (!data.isEmpty()) {
        emit dataReceived(data);
    }
}

// 连接到串口
bool SerialManager::connectPort(const QString &portName, int baudRate,
                                QSerialPort::DataBits dataBits,
                                QSerialPort::Parity parity,
                                QSerialPort::StopBits stopBits,
                                QSerialPort::FlowControl flowControl)
{
    // 设置端口参数
    serialPort->setPortName(portName);
    serialPort->setBaudRate(baudRate);
    serialPort->setDataBits(dataBits);
    serialPort->setParity(parity);
    serialPort->setStopBits(stopBits);
    serialPort->setFlowControl(flowControl);

    // 打开串口
    bool success = serialPort->open(QIODevice::ReadWrite);
    if (success) {
        emit connectionStatusChanged(true);
        return true;
    } else {
        lastError = serialPort->errorString();
        emit errorOccurred(lastError);
        return false;
    }
}

// 断开串口连接
void SerialManager::disconnectPort()
{
    if (serialPort->isOpen()) {
        QString portName = serialPort->portName();
        serialPort->close();
        
        // 更新端口状态
        if (portInfoCache.contains(portName)) {
            portInfoCache[portName].isConnectedByApp = false;
            updatePortDisplayText(portInfoCache[portName]);
        }
        
        // 发出连接状态变化信号
        emit connectionStatusChanged(false);
    }
}

QList<SerialPortInfo> SerialManager::getAvailablePorts() const
{
    QList<SerialPortInfo> list;
    for (auto it = portInfoCache.constBegin(); it != portInfoCache.constEnd(); ++it) {
        const SerialPortInfo &info = it.value();
        list.append(info);
    }
    return list;
}

void SerialManager::handleError(QSerialPort::SerialPortError error)
{
    if (error == QSerialPort::NoError) {
        return;
    }

    // 记录错误信息并通知上层
    lastError = serialPort->errorString();
    emit errorOccurred(lastError);

    // 对严重错误进行断开处理并刷新端口状态
    if (error == QSerialPort::ResourceError ||
        error == QSerialPort::PermissionError ||
        error == QSerialPort::DeviceNotFoundError ||
        error == QSerialPort::OpenError) {
        disconnectPort();
        updatePortStatusCache();
        emit portStatusChanged();
    }
}